package com.htudata.transctFlow.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.htudata.alarm.pojo.po.AlarmLevelPO;
import com.htudata.alarm.service.AlarmLevelService;
import com.htudata.common.enums.PageSeqEnum;
import com.htudata.common.enums.RequestSeqEnum;
import com.htudata.common.service.DataEhcacheService;
import com.htudata.common.service.TokenService;
import com.htudata.common.vo.ResponseResult;
import com.htudata.core.util.ResultGenerator;
import com.htudata.core.util.operation.*;
import com.htudata.transctFlow.dao.TransctFlowDao;
import com.htudata.transctLive.dao.TransctLiveDao;
import com.htudata.transctLive.pojo.entity.TransctFlow;
import com.htudata.transctLive.pojo.vo.TransctFlowGraphicDisplayVo;
import com.htudata.transctLive.service.TransctFlowService;
import com.htudata.transctLive.service.TransctLiveService;
import com.htudata.trigger.service.TriggerService;
import com.htudata.user.dao.UserDao;
import com.htudata.user.service.UserService;
import com.htudata.websocket.endpoint.AgentServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class TransctFlowShowService {

  @Autowired
  private TransctLiveService liveService;
  
  @Autowired
  private TransctFlowService flowService;
  
  @Autowired
  private AlarmLevelService alarmLevelService;
  
  @Autowired
  private UserService userService;
  
  @Autowired
  private DataEhcacheService dataEhcacheService;
  
  @Autowired
  private AgentServerEndpoint agentServerEndpoint;
  
  @Autowired
  private TriggerService triggerService;
  
  @Autowired
  private TransctFlowDao flowDao;
  
  @Autowired
  private TransctLiveDao liveDao;
  
  @Autowired
  private UserDao userDao;
  
  @Value("${internal_3d_flow_status}")
  private String internal_3d_flow_status;
  
  @Value("${view_transct_flow_count}")
  private int view_transct_flow_count;
  
  public String get3DFlowsTemp(String flowId, String a2Info) throws Exception {
    try {
      List<TransctFlowGraphicDisplayVo> resultFlows = new ArrayList<>();
      List<TransctFlow> flows = this.flowDao.selectFlows(null, null);
      int flowIndex = 0;
      int index = -1;
      boolean add = false;
      for (TransctFlow flow : flows) {
        index++;
        if (flowId.equals(flow.getFlowId())) {
          flowIndex = index;
          add = true;
        } 
        if (add)
          resultFlows.addAll(get3DFlowsTemp2(flow.getFlowId(), a2Info)); 
        if (resultFlows.size() == this.view_transct_flow_count)
          break; 
      } 
      if (resultFlows.size() < this.view_transct_flow_count) {
        int index2 = -1;
        for (TransctFlow flow : flows) {
          index2++;
          if (flowIndex == index2)
            break; 
          resultFlows.addAll(get3DFlowsTemp2(flow.getFlowId(), a2Info));
          if (resultFlows.size() == this.view_transct_flow_count)
            break; 
        } 
      } 
      String result = JSON.toJSONString(
          ResultGenerator.genResult(RequestSeqEnum.SEQ_006.getCode(), resultFlows, "获取事务流程图数据成功"));
      return result;
    } catch (Exception e) {
      throw e;
    } 
  }
  
  public List<TransctFlowGraphicDisplayVo> get3DFlowsTemp2(String flowId, String a2Info) throws Exception {
    try {
      long userId = TokenService.getUserId(a2Info);
      long roleType = TokenService.getRoleType(a2Info);
      List<AlarmLevelPO> alarmLevelList = this.alarmLevelService.getAlarmLevelList("");
      ResponseResult origin3DFlows = this.liveService.get3DFlows(RequestSeqEnum.SEQ_006.getCode(), false, flowId, 1, 0, "", userId);
      List<TransctFlowGraphicDisplayVo> flowGraphicVoListOrigin = (List<TransctFlowGraphicDisplayVo>)origin3DFlows.getData();
      this.flowService.setNodeAlarms(flowGraphicVoListOrigin, flowId, true, "", alarmLevelList, -1L);
      return flowGraphicVoListOrigin;
    } catch (Exception e) {
       throw e;
    } 
  }
  
  public void send3DFlows()  throws Exception{
    try {
      Map<String, List<Long>> currentFlowsAndUserIds = this.agentServerEndpoint.getCurrentTransctFlowsAndUserIds();
      if (!MapOperationUtils.isValidMap(currentFlowsAndUserIds))
        return; 
      JSONArray mngUserIds = this.userDao.selectUserIdsByRoleType(1L);
      JSONObject mngUserIdJO = FastJsonOperationUtils.JSONArrayToJSONObejct(mngUserIds, "userId", false);
      List<AlarmLevelPO> alarmLevelList = this.alarmLevelService.getAlarmLevelList("");
      Map<String, String> flows = new HashMap<>();
      String flowId = null;
      List<Long> userIds = null;
      ResponseResult origin3DFlows = null;
      JSONObject origin3DFlowsJO = null;
      JSONObject origin3DFlowsJOTemp = null;
      List<TransctFlowGraphicDisplayVo> flowGraphicVoListOrigin = null;
      for (Map.Entry<String, List<Long>> entry : currentFlowsAndUserIds.entrySet()) {
        flowId = entry.getKey();
        userIds = (List<Long>)((List)entry.getValue()).stream().distinct().collect(Collectors.toList());
        origin3DFlows = this.liveService.get3DFlows(RequestSeqEnum.SEQ_006.getCode(), true, flowId, 1, 0, "", -1L);
        origin3DFlowsJO = (JSONObject)JSON.toJSON(origin3DFlows);
        for (Iterator<Long> iterator = userIds.iterator(); iterator.hasNext(); ) {
          long userId = iterator.next().longValue();
          origin3DFlowsJOTemp = (JSONObject)origin3DFlowsJO.clone();
          flowGraphicVoListOrigin = origin3DFlowsJOTemp.getObject("data", (TypeReference)new Object());
          boolean hasNodeStatis = true;
          this.flowService.setNodeAlarms(flowGraphicVoListOrigin, flowId, true, "", alarmLevelList, -1L);
          origin3DFlowsJOTemp.put("data", flowGraphicVoListOrigin);
          flows.put(flowId + "_" + userId, 
              get3DFlowsTemp(flowId, userId, origin3DFlowsJOTemp.toJSONString(), hasNodeStatis));
        } 
      } 
      this.agentServerEndpoint.sendTransctFlows(flows);
    } catch (Exception e) {
      throw e;
    } 
  }
  
  public String get3DFlowsTemp(String flowId, long userId, String newJson, boolean hasNodeStatis) {
    String result = newJson;
    if (hasNodeStatis)
      return result; 
    Object temp = this.dataEhcacheService.getValueFromCache(RequestSeqEnum.SEQ_006.getCode() + "_" + flowId + "_" + userId);
    if (temp != null) {
      String oldJson = (String)temp;
      if (oldJson.equals(result))
        return null; 
    } 
    this.dataEhcacheService.putValueToCache(RequestSeqEnum.SEQ_006.getCode() + "_" + flowId + "_" + userId, result);
    return result;
  }
  
  public JSONArray getInternal3DFlowsInfo() {
    return this.flowDao.getInternal3DFlowsInfo(this.internal_3d_flow_status);
  }
  
  public Object getGivenFlowsAndNodesOfUser(long userId) throws Exception {
    JSONObject userInfo = this.userService.getUserInfo(userId);
    long roleType = userInfo.getLongValue("roleType");
    JSONArray allDataType = this.liveDao.getAllDataType();
    JSONObject dataType = null;
    for (Object obj : allDataType) {
      dataType = (JSONObject)obj;
      dataType.put("flows", new JSONArray());
    } 
    JSONObject dataTypeJO = FastJsonOperationUtils.JSONArrayToJSONObejct(allDataType, "dataTypeId", false);
    JSONObject selectedFlowIdJO = null;
    JSONObject selectedNodeIdJO = null;
    if (roleType != -1L && roleType != 1L) {
      selectedFlowIdJO = FastJsonOperationUtils.JSONArrayToJSONObejct(this.flowDao.selectFlowIdByUser(userId), "flow_id", false);
      selectedNodeIdJO = FastJsonOperationUtils.JSONArrayToJSONObejct(this.flowDao.selectNodeIdByUser(userId), "node_id", false);
    } 
    JSONArray flows = this.flowService.getFlowGraphicDisplayVoList3(0, 0, -1, 0, 0, 0, "").getJSONArray("data");
    JSONObject flow = null;
    JSONObject node = null;
    for (Object obj : flows) {
      flow = (JSONObject)obj;
      if (!dataTypeJO.containsKey(flow.getString("dataTypeId")))
        continue; 
      dataTypeJO.getJSONObject(flow.getString("dataTypeId")).getJSONArray("flows").add(flow);
      flow.remove("dataTypeId");
      if (roleType == 1L) {
        flow.put("isSelected", Integer.valueOf(1));
        for (Object obj2 : flow.getJSONArray("nodes")) {
          node = (JSONObject)obj2;
          node.put("isSelected", Integer.valueOf(1));
        } 
        continue;
      } 
      if (selectedFlowIdJO.containsKey(flow.getString("flowId"))) {
        flow.put("isSelected", Integer.valueOf(1));
      } else {
        flow.put("isSelected", Integer.valueOf(0));
      } 
      for (Object obj2 : flow.getJSONArray("nodes")) {
        node = (JSONObject)obj2;
        if (selectedNodeIdJO.containsKey(node.getString("nodeId"))) {
          node.put("isSelected", Integer.valueOf(1));
          continue;
        } 
        node.put("isSelected", Integer.valueOf(0));
      } 
    } 
    JSONObject dataTypeTemp = null;
    for (Map.Entry<String, Object> entry : (Iterable<Map.Entry<String, Object>>)dataTypeJO.entrySet()) {
      dataTypeTemp = (JSONObject)entry.getValue();
      if (!CollectionsOperationUtils.isValidCollection((Collection)dataTypeTemp.getJSONArray("flows")))
        entry.setValue(null); 
    } 
    JSONArray result = (JSONArray)JSON.toJSON(MapOperationUtils.getMapValForList((Map)dataTypeJO));
    result.removeAll(Collections.singleton(null));
    FastJsonOperationUtils.sortByLongField(result, "dataTypeId", "asc");
    return result;
  }
  
  public Object getResourceTree(int resourceType, String flowName, String nodeNickName, String triggerName) throws Exception {
    JSONArray allDataType = this.liveDao.getAllDataType();
    if (1 == resourceType)
      return allDataType; 
    JSONObject dataType = null;
    for (Object obj : allDataType) {
      dataType = (JSONObject)obj;
      dataType.put("flows", new JSONArray());
    } 
    JSONObject dataTypeJO = FastJsonOperationUtils.JSONArrayToJSONObejct(allDataType, "dataTypeId", false);
    JSONArray flows = this.flowService.getFlowGraphicDisplayVoList4(0, 0, -1, 0, 0, 0, "", flowName, nodeNickName).getJSONArray("data");
    JSONObject triggerJO = null;
    if (4 == resourceType) {
      triggerJO = new JSONObject();
      JSONArray triggerList = this.triggerService.getTriggerList("0", "0", 1, triggerName);
      JSONObject triggerTemp = null;
      JSONArray triggerTempList = null;
      for (Object obj : triggerList) {
        triggerTemp = (JSONObject)obj;
        if (triggerJO.containsKey(triggerTemp.getString("nodeId"))) {
          triggerJO.getJSONArray(triggerTemp.getString("nodeId")).add(triggerTemp);
          continue;
        } 
        triggerTempList = new JSONArray();
        triggerTempList.add(triggerTemp);
        triggerJO.put(triggerTemp.getString("nodeId"), triggerTempList);
      } 
    } 
    JSONObject flow = null;
    JSONObject node = null;
    JSONArray nodeList = null;
    for (Object obj : flows) {
      flow = (JSONObject)obj;
      if (!dataTypeJO.containsKey(flow.getString("dataTypeId")))
        continue; 
      if (4 == resourceType) {
        nodeList = new JSONArray();
        for (Object obj2 : flow.getJSONArray("nodes")) {
          node = (JSONObject)obj2;
          if (triggerJO.containsKey(node.getString("nodeId"))) {
            node.put("triggers", triggerJO.getJSONArray(node.getString("nodeId")));
            nodeList.add(node);
          } 
        } 
        if (!CollectionsOperationUtils.isValidCollection((Collection)nodeList))
          continue; 
        flow.put("nodes", nodeList);
      } 
      if (2 == resourceType)
        flow.remove("nodes"); 
      dataTypeJO.getJSONObject(flow.getString("dataTypeId")).getJSONArray("flows").add(flow);
      flow.remove("dataTypeId");
    } 
    JSONObject dataTypeTemp = null;
    for (Map.Entry<String, Object> entry : (Iterable<Map.Entry<String, Object>>)dataTypeJO.entrySet()) {
      dataTypeTemp = (JSONObject)entry.getValue();
      if (!CollectionsOperationUtils.isValidCollection((Collection)dataTypeTemp.getJSONArray("flows")))
        entry.setValue(null); 
    } 
    JSONArray result = (JSONArray)JSON.toJSON(MapOperationUtils.getMapValForList((Map)dataTypeJO));
    result.removeAll(Collections.singleton(null));
    FastJsonOperationUtils.sortByLongField(result, "dataTypeId", "asc");
    return result;
  }
  
  public String getTransctFlows(boolean needJudgeChange, List<Integer> statusList)  throws Exception{
    ResponseResult responseResult = null;
    try {
      responseResult = ResultGenerator.genResult(RequestSeqEnum.SEQ_007.getCode(), this.flowDao
          .selectFlows(statusList, null), "获取已发布事务流程列表成功");
    } catch (Exception e) {
       throw e;
    } 
    String result = JSON.toJSONString(responseResult);
    if (!needJudgeChange)
      return result; 
    Object temp = this.dataEhcacheService.getValueFromCache(RequestSeqEnum.SEQ_007.getCode());
    if (temp != null) {
      String oldJson = (String)temp;
      if (oldJson.equals(result))
        return null; 
    } 
    this.dataEhcacheService.putValueToCache(RequestSeqEnum.SEQ_007.getCode(), result);
    return result;
  }
  
  public String getTransctFlowHealthStatis(String transctFlowId, String a2Info) throws Exception {
    try {
      if (StringOperationUtils.isValidStr2(transctFlowId) && !"-1".equals(transctFlowId))
        if ("all".equals(transctFlowId)) {
          String result = JSON.toJSONString(ResultGenerator.genResult(RequestSeqEnum.SEQ_010.getCode(), this.flowDao
                .getTransctFlowHealthStatis(transctFlowId), "获取事务流程健康度统计成功"));
          return result;
        }  
    } catch (Exception e) {
      throw e;
    } 
    return null;
  }
  
  public String getTransctFlowHealthRanking(String transctFlowId, String rankingType, int year, String field, String sort, int page, int perPage, String a2Info)  throws Exception{
    try {
      String result = null;
      if (StringOperationUtils.isValidStr2(transctFlowId) && !"-1".equals(transctFlowId))
        if ("all".equals(transctFlowId) && 
          StringOperationUtils.isValidStr2(rankingType) && "transctFlow".equals(rankingType)) {
          JSONArray ja = this.flowDao.getTransctFlowLeaderBoard(transctFlowId, year, field, sort, 
              getRowIndex(page, perPage), perPage);
          JSONObject jo = new JSONObject();
          jo.put("list", ja.getJSONArray(0));
          jo.put("total", ((HashMap)((ArrayList<HashMap>)ja.get(1)).get(0))
              .get("total"));
          jo.put("page", Integer.valueOf(page));
          jo.put("perPage", Integer.valueOf(perPage));
          result = JSON.toJSONString(
              ResultGenerator.genResult(RequestSeqEnum.SEQ_011.getCode(), jo, "获取获取事务流程健康度排行榜成功"));
          return result;
        }  
    } catch (Exception e) {
      throw e;
    } 
    return null;
  }
  
  public static int getRowIndex(int pageNum, int pageSize) {
    return (pageNum > 0) ? ((pageNum - 1) * pageSize) : 0;
  }
  
  public String getTransctFlowHealthStatis(boolean needJudgeChange)  throws Exception{
    ResponseResult responseResult = null;
    try {
      responseResult = ResultGenerator.genResult(RequestSeqEnum.SEQ_010.getCode(), this.flowDao
          
          .getTransctFlowHealthStatis("all"), "获取事务流程健康度统计成功");
    } catch (Exception e) {
      throw e;
    } 
    String result = JSON.toJSONString(responseResult);
    if (!needJudgeChange)
      return result; 
    Object temp = this.dataEhcacheService.getValueFromCache(RequestSeqEnum.SEQ_010.getCode());
    if (temp != null) {
      String oldJson = (String)temp;
      if (oldJson.equals(result))
        return null; 
    } 
    this.dataEhcacheService.putValueToCache(RequestSeqEnum.SEQ_010.getCode(), result);
    return result;
  }
  
  public void sendTransctFlowHealthRanking()  throws Exception{
    Map<String, String> transctFlowHealthRankingTempMap = new HashMap<>();
    AgentServerEndpoint agentServerEndpointTemp = null;
    for (Map.Entry<String, AgentServerEndpoint> entry : this.agentServerEndpoint.getAgentServerEndpoints().entrySet()) {
      agentServerEndpointTemp = entry.getValue();
      if (!agentServerEndpointTemp.getAppCode().equals(PageSeqEnum.SEQ_001.getCode()))
        continue; 
      if (!agentServerEndpointTemp.getInterfaceInfos().containsKey(RequestSeqEnum.SEQ_011.getCode()))
        continue; 
      JSONObject interfaceParamBody = (JSONObject)agentServerEndpointTemp.getInterfaceInfos().get(RequestSeqEnum.SEQ_011.getCode());
      try {
        String transctFlowHealthRankingTemp = null;
        String key = RequestSeqEnum.SEQ_011.getCode() + "-" + interfaceParamBody.getString("transctFlowId") + "-" + interfaceParamBody.getString("rankingType") + "-" + interfaceParamBody.getIntValue("year") + "-" + interfaceParamBody.getString("field") + "-" + interfaceParamBody.getString("sort") + "-" + interfaceParamBody.getIntValue("page") + "-" + interfaceParamBody.getIntValue("perPage");
        if (transctFlowHealthRankingTempMap.containsKey(key)) {
          transctFlowHealthRankingTemp = transctFlowHealthRankingTempMap.get(key);
        } else {
          transctFlowHealthRankingTemp = getTransctFlowHealthRanking(interfaceParamBody
              .getString("transctFlowId"), interfaceParamBody.getString("rankingType"), interfaceParamBody
              .getIntValue("year"), interfaceParamBody.getString("field"), interfaceParamBody
              .getString("sort"), interfaceParamBody.getIntValue("page"), interfaceParamBody
              .getIntValue("perPage"), null);
          transctFlowHealthRankingTempMap.put(key, transctFlowHealthRankingTemp);
        } 
        String transctFlowHealthRanking = getTransctFlowHealthRanking(key, transctFlowHealthRankingTemp);
        if (StringOperationUtils.isValidStr2(transctFlowHealthRanking))
          agentServerEndpointTemp.sendMessage(transctFlowHealthRanking); 
      } catch (Exception e) {
        throw e;
      } 
    } 
  }
  
  public String getTransctFlowHealthRanking(String key, String newJson) {
    String result = newJson;
    Object temp = this.dataEhcacheService.getValueFromCache(key);
    if (temp != null) {
      String oldJson = (String)temp;
      if (oldJson.equals(result))
        return null; 
    } 
    this.dataEhcacheService.putValueToCache(key, result);
    return result;
  }
}
